#ifndef EDGES_HPP
#define EDGES_HPP

#include "edgesBase.hpp"
#include "edge.hpp"

#include <vector>


namespace hms {

template<>
class EdgesTraits<Edges>
{
public:
	using MeshType = Mesh;
	using NormalsReturnType = const Matrix2Xs&;
	using LengthsReturnType = const ArrayXs&;
};

/**
 * @class Edges
 * @author lenni
 * @date 19/03/20
 * @file edges.h
 * @brief Stores all edge properties and provides efficient access
 * 
 * Struct of arrays which stores the properties of each edge, such as
 * the indices of its vertices, length, normal vector, parent cells and whether
 * it is a boundary cell.
 * Can be accessed through the proxy object hms::Edge, which itself is accessed
 * by calling hms::Mesh::edge(Index).
 */
class Edges : public EdgesBase<Edges>
{
public:
	using Traits = EdgeTraits<Edge>;

private:
	Index m_nInnerEdges {signalCode::uninitialised};
	
	/* for each edge, the indices for its two endpoints are stored */
	Array2Xi m_vertices;
	ArrayXs  m_lengths;
	Matrix2Xs m_normals;
	
	/* each edge has two adjacent cells */
	Array2Xi m_cells;
	

public:
	Edges() = default;
	
	Edges( const Mesh& );
	
	auto vertices() const -> const Array2Xi&;

	#ifndef STRUCTMESH_PRECALC_EDGE_PARENT_CELLS
	auto cells   () const -> const Array2Xi&;
	#else
	using EdgesBase<Edges>::cells;
	#endif

	auto nEdges        () const -> Index;
	auto nInnerEdges   () const -> Index;
	auto nBoundaryEdges() const -> Index;
	
	auto length      (Index) const -> scalar;
	auto vertices    (Index) const -> Traits::VertexIndices;
	auto cells_s     (Index) const -> Traits::CellIndices;
	auto normal      (Index) const -> Traits::NormalVector;
	auto midpoint    (Index) const -> Vector2s;
	auto intersection(Index) const -> Vector2s;
	auto isBoundary  (Index) const -> bool;
	auto domainCell  (Index) const -> Index;
	auto ghostCell   (Index) const -> Index;

private:
	auto cellsImp  (Index) const -> const Array2Xi&;
	auto lengthsImp() const -> const ArrayXs&;
	auto normalsImp() const -> const Matrix2Xs&;

	void nInnerEdges(Index);
	void vertices( Array2Xi&& );
	void cells( Array2Xi&& );
	
	void storeData(
		Index nInnerEdges,
		Array2Xi&& vertexIndices,
		Array2Xi&& cells
	);

	void swap(Index, Index);
	
	void storeLengths();
	void storeNormals();
	
	friend class Mesh;
	friend EdgesBase;
};

} // end namespace hms

#endif